package org.codefinger.dao.callback;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.codefinger.dao.impl.ResultSetCallback;
import org.codefinger.dao.util.jdbc.JDBCUtil;
import org.codefinger.dao.util.jdbc.ResultSetGetter;
import org.codefinger.dao.util.magic.MagicAttribute;
import org.codefinger.dao.util.magic.MagicConstructor;
import org.codefinger.dao.util.magic.MagicPojo;

public class PojoListQueryCallback<T> implements ResultSetCallback<List<T>> {

	private MagicConstructor<T>	constructor;

	private AttrItemSetter[]	attrItemSetters;

	public PojoListQueryCallback(Class<T> pojoClass, String[] aliases) {
		super();
		MagicPojo<T> magicPojo = MagicPojo.getMagicPojo(pojoClass);
		int length = aliases.length;
		List<AttrItemSetter> attrItemSetters = new ArrayList<AttrItemSetter>(length);
		MagicAttribute magicAttribute;
		int index = 0;
		for (String alias : aliases) {
			index++;
			magicAttribute = magicPojo.getMagicAttribute(alias);
			if (magicAttribute == null) {
				magicAttribute = magicPojo.getMagicAttributeByUpperCase(alias.toUpperCase());
			}
			if (magicAttribute == null) {
				continue;
			}
			attrItemSetters.add(new AttrItemSetter(magicAttribute, JDBCUtil.getRSGetter(magicAttribute.getField().getType()), index));
		}
		this.constructor = magicPojo.getConstructor();
		this.attrItemSetters = attrItemSetters.toArray(new AttrItemSetter[attrItemSetters.size()]);
	}

	@Override
	public List<T> getResult(ResultSet resultSet, String[] aliases) throws SQLException {
		AttrItemSetter[] attrItemSetters = this.attrItemSetters;
		MagicConstructor<T> constructor = this.constructor;
		List<T> list = new ArrayList<T>();
		T pojo;
		while (resultSet.next()) {
			pojo = constructor.newInstance();
			for (AttrItemSetter attrItemSetter : attrItemSetters) {
				attrItemSetter.setValue(pojo, resultSet);
			}
			list.add(pojo);
		}
		return list;
	}

	protected static class AttrItemSetter {

		private MagicAttribute	magicAttribute;

		private ResultSetGetter	resultSetGetter;

		private int				index;

		public AttrItemSetter(MagicAttribute magicAttribute, ResultSetGetter resultSetGetter, int index) {
			super();
			this.magicAttribute = magicAttribute;
			this.resultSetGetter = resultSetGetter;
			this.index = index;
		}

		public void setValue(Object target, ResultSet resultSet) throws SQLException {
			Object value = resultSetGetter.getResult(resultSet, index);
			if (value == null) {
				return;
			}
			magicAttribute.setValue(target, value);
		}
	}

}
